package com.dingreading.cloud.admin.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.admin.dto.GoodsAndTypeDto;
import com.dingreading.cloud.admin.dto.GoodsTypeDto;
import com.dingreading.cloud.admin.dto.vo.GoodsTypeInAndSendVo;
import com.dingreading.cloud.admin.dto.vo.WhStockInVo;
import com.dingreading.cloud.admin.entity.*;
import com.dingreading.cloud.admin.service.*;
import com.dingreading.cloud.admin.util.bean.GoodsWetAvgUtil;
import com.dingreading.cloud.admin.util.bean.PurchaseUtil;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/system/whStockIn")
@Api(tags = "总部-仓库入库管理")
public class WhStockInController {

    @Resource
    protected WhPurchaseService whPurchaseService;
    @Resource
    protected WhPurchaseGoodsService whPurchaseGoodsService;
    @Resource
    protected WhStockInService stockInService;
    @Resource
    protected GoodsTypeService goodsTypeService;
    @Resource
    protected GoodsWetPriceService goodsWetPriceService;
    @Resource
    protected WhStockOutGoodsService stockOutGoodsService;


    @ApiOperation(value = "分页列表")
    @PostMapping(value = "/pageList", produces = "application/json; charset=UTF-8")
    public R<Object> pageList(
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库单号/采购单号/商品名/商品规格名/供应商") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "供应商id") @RequestParam(value = "suppliersId", required = false) Long suppliersId,
            @ApiParam(value = "状态 1.入库完成 2.入库中 -1.入库已退回") @RequestParam(value = "status", required = false) Integer status,
            @ApiParam(value = "活动开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "活动结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) {
        Page<WhStockIn> page = this.stockInService.pageList(pageUtil, keyword, status, beginDate, endDate);

        PageBeanDto data = new PageBeanDto();
        data.setTotal(page.getTotalRow());
        data.setList(page.getRecords());
        return R.ok(data);
    }


    @ApiOperation(value = "分页列表")
    @PostMapping(value = "/returnList", produces = "application/json; charset=UTF-8")
    public R<Object> returnList(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "入库单号/采购单号/商品名/商品规格名/供应商") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "状态 1.入库完成 -1.入库已退回") @RequestParam(value = "status", required = false) Integer status
    ) {
        Page<WhStockIn> page = this.stockInService.returnList(pageUtil, keyword, status);

        PageBeanDto data = new PageBeanDto();
        data.setTotal(page.getTotalRow());
        data.setList(page.getRecords());
        return R.ok(data);
    }


    @ApiOperation(value = "获取详情")
    @PostMapping(value = "/get", produces = "application/json; charset=UTF-8")
    public R<Object> get(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库记录code") @RequestParam(value = "inCode") String inCode
    ) {
        WhStockIn data = stockInService.getByInCode(inCode);
        if (data == null) return R.fail("入库记录获取失败");

        return R.ok(data);
    }


    @ApiOperation(value = "删除入库记录")
    @PostMapping(value = "/dropBean", produces = "application/json; charset=UTF-8")
    public R<Object> dropBean(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库记录code") @RequestParam(value = "inCode") String inCode
    ) {
        WhStockIn data = stockInService.getByInCode(inCode);
        if (data == null) return R.fail("入库记录获取失败");
        if (data.getStatus().equals(1)) return R.fail("入库记录已完成，不能删除");

        WhPurchaseGoods goods = whPurchaseGoodsService.getById(data.getPurchaseGoodsId());
        if (goods == null) return R.fail("采购商品获取失败");
        if (goods.getStatus().equals(EnumType.Purchase.CANCEL.getType())) return R.fail("采购商品已取消，不能操作");
        if (goods.getStatus().equals(EnumType.Purchase.OK.getType())) return R.fail("采购商品已完成，不能操作");

        WhPurchase purchase = whPurchaseService.getByCode(goods.getPurchaseCode());
        if (purchase == null) return R.fail("采购订单获取失败");
        ArrayList<Integer> okStatusList = Lists.newArrayList(EnumType.Purchase.STEP_1.getType(), EnumType.Purchase.STEP_2.getType());
        if (!okStatusList.contains(purchase.getStatus()))
            return R.fail("操作失败订单当前状态：" + EnumType.Purchase.getStatus(purchase.getStatus()));

        long l = stockInService.dropData(inCode);
        if (l <= 0) return R.fail("删除失败");
        // 删除成功，相关状态更改...

        long l1 = stockInService.getByPurchaseIdCnt(data.getPurchaseGoodsId());
        if (l1 <= 0) {
            // 更新采购商品记录为待入库
            whPurchaseGoodsService.updateWaitIn(data.getPurchaseGoodsId());
            // 没有商品入库记录时，更新采购订单为待入库
            long l2 = stockInService.getPurchaseCodeCnt(data.getPurchaseCode(), null);
            if (l2 <= 0)
                whPurchaseService.updateWaitIn(data.getPurchaseCode());
        }
        return R.ok();
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "添加/修改入库记录")
    @PostMapping(value = "/newBean")
    public R<Object> newBean(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "采购商品id") @RequestParam(value = "purchaseGoodsId") Long purchaseGoodsId,
            @ApiParam(value = "id") @RequestParam(value = "id", required = false) Long id,
            @ApiParam(value = "实际入库数") @RequestParam(value = "realNum", required = false) Integer realNum,
            @ApiParam(value = "入库备注") @RequestParam(value = "remark", required = false) String remark
    ) throws Exception {
        if (realNum == null || realNum <= 0) return R.fail("入库数量必须大于0");

        WhPurchaseGoods goods = whPurchaseGoodsService.getById(purchaseGoodsId);
        if (goods == null) return R.fail("采购商品记录获取失败");
        if (goods.getStatus().equals(EnumType.Purchase.CANCEL.getType()))
            return R.fail("采购商品记录已取消，不能操作");
        if (goods.getStatus().equals(EnumType.Purchase.OK.getType())) return R.fail("采购商品记录已完成，不能操作");

        WhPurchase purchase = whPurchaseService.getByCode(goods.getPurchaseCode());
        if (purchase == null) return R.fail("采购订单获取失败");
        ArrayList<Integer> okStatusList = Lists.newArrayList(EnumType.Purchase.STEP_1.getType(), EnumType.Purchase.STEP_2.getType());
        if (!okStatusList.contains(purchase.getStatus()))
            return R.fail("操作失败采购订单当前状态：" + EnumType.Purchase.getStatus(purchase.getStatus()));

        if (id == null || id <= 0) {
            // 新增
            WhStockIn data = PurchaseUtil.newStockIn(headStaffUid, headStaffName, goods, realNum, remark);
            stockInService.saveOrUpdate(data);
            // 更新采购商品信息
//            goods.setStatus(EnumType.Purchase.STEP_2.getType());
//            goods.setStatusName(EnumType.Purchase.STEP_2.getName());
//            whPurchaseGoodsService.saveOrUpdate(goods);
            // 采购商品信息设置为入库中
            boolean l = whPurchaseGoodsService.updateEntering(goods.getId());
            // 更新采购订单信息
            if (!purchase.getStatus().equals(EnumType.Purchase.STEP_2.getType())) {
//                purchase.setStatus(EnumType.Purchase.STEP_2.getType());
//                purchase.setStatusName(EnumType.Purchase.STEP_2.getName());
//                whPurchaseService.saveOrUpdate(purchase);
                whPurchaseService.updateEntering(goods.getPurchaseCode());
            }
        } else {
            // 修改
            WhStockIn data = stockInService.getById(id);
            if (data == null) return R.fail("入库记录获取失败");
            if (data.getStatus().equals(1)) return R.fail("入库已完成，不能修改");

            data.setRealNum(realNum);
            data.setRemark(remark);
            stockInService.saveOrUpdate(data);
        }
        return R.ok();
    }


    @ApiOperation(value = "根据采购商品id获取入库记录")
    @PostMapping(value = "/getByPurchaseId", produces = "application/json; charset=UTF-8")
    public R<Object> getByPurchaseId(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "采购商品id") @RequestParam(value = "purchaseId") Long purchaseId
    ) {
        List<WhStockIn> data = stockInService.getByPurchaseId(purchaseId);

        return R.ok(data);
    }


    @ApiOperation(value = "验证入库记录是否可以完成")
    @PostMapping(value = "/authInOk", produces = "application/json; charset=UTF-8")
    public R<Object> authInOk(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库订单号") @RequestParam(value = "inCode") String inCode
    ) {
        WhStockIn data = stockInService.getByInCode(inCode);
        if (data == null) return R.fail("入库订单获取失败");
        if (!data.getStatus().equals(2)) return R.fail("操作失败状态需要是入库中");

        int realNumCnt = stockInService.getRealNumCnt(data.getPurchaseGoodsId());
        int numCnt = realNumCnt + data.getRealNum();
        if (numCnt > data.getBuyNum()) {
            return R.fail(0, "采购总数：" + data.getBuyNum() + "，已入库总数：" + realNumCnt + "，本次入库数：" + data.getRealNum());
        }
        return R.ok();
    }


    @ApiOperation(value = "入库订单设置入库完成")
    @PostMapping(value = "/setOk", produces = "application/json; charset=UTF-8")
    public R<Object> setOk(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库订单号") @RequestParam(value = "inCode") String inCode
    ) {
        WhStockIn data = stockInService.getByInCode(inCode);
        if (null == data) return R.fail("入库订单获取失败");
        if (!data.getStatus().equals(2)) return R.fail("操作失败状态需要是入库中");

        WhPurchaseGoods purchaseGoods = whPurchaseGoodsService.getById(data.getPurchaseGoodsId());
        if (null == purchaseGoods) return R.fail("采购商品记录获取失败");
        int realNumCnt = NepUtil.nullToZero(purchaseGoods.getRealNum());
        int buyNum = NepUtil.nullToZero(purchaseGoods.getBuyNum());
        double unitPrice = NepUtil.nullToZero(purchaseGoods.getUnitPrice());

        int realNum = NepUtil.nullToZero(data.getRealNum());

        // 计算此次的入库金额
        double inAmount = 0;
        if (realNum > 0 && realNumCnt == 0 && realNum == buyNum) {
            // 第一次入库，并且此次入库数与采购商品数相等
            inAmount = NepUtil.nullToZero(purchaseGoods.getPrice());
        } else {
            if (realNumCnt >= buyNum) {
                // 已入库数量大于等于商品采购数，此次的入库金额为0
                inAmount = 0;
            } else {
                realNumCnt = realNumCnt + realNum;
                if (realNumCnt <= buyNum) {
                    // 此次入库数量+ 已入库数量<=商品采购数
                    inAmount = DoubleUtil.mul(realNum, unitPrice);
                } else {
                    // 此次入库数量+ 已入库数量超过了商品采购数
                    // 计算多出的数量
                    int i = realNumCnt - buyNum;
                    // 此次入库数量-多出的数量
                    int j = realNum - i;
                    inAmount = DoubleUtil.mul(j, unitPrice);
                }
            }
        }

        Date time = DateUtil.getNowDatetime();
        boolean l = stockInService.setOk(inCode, headStaffUid, headStaffName, realNum, inAmount, time);
        if (!l) return R.fail("完成入库失败");

        // 商品入库，计算入库商品的加权平均价
        GoodsWetAvgUtil.updateGoodsWetAvgPrice(data.getGoodsName() + "-" + data.getGoodsTypeName(), data.getGoodsId(),
                data.getGoodsTypeId(), realNum, inAmount);
        return R.ok();
    }


    @ApiOperation(value = "退回入库单的库存数")
    @PostMapping(value = "/returnStockIn", produces = "application/json; charset=UTF-8")
    public R<Object> returnStockIn(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库记录单号") @RequestParam(value = "inCode") String inCode,
            @ApiParam(value = "备注") @RequestParam(value = "remark") String remark
    ) {
        WhStockIn stockIn = stockInService.getByInCode(inCode);
        if (null == stockIn) return R.fail("入库单获取失败");
        if (stockIn.getStatus().equals(2)) return R.fail("未入库，不能操作");
        if (stockIn.getStatus().equals(-1)) return R.fail("入库已退回，不能操作");
        if (stockIn.getUsableNum() <= 0) return R.fail("剩余入库数量为0，不能操作");

        WhPurchaseGoods purchaseGoods = whPurchaseGoodsService.getById(stockIn.getPurchaseGoodsId());
        if (null == purchaseGoods) return R.fail("采购的商品记录获取失败");
        // 采购订单已完成，不能退，按出库处理
        if (!purchaseGoods.getStatus().equals(EnumType.Purchase.STEP_2.getType()))
            return R.fail("采购订单的状态为已完成，不能操作");
        // 采购订单未完成，入库单的数量已使用或用完，也不能退
        if (!NepUtil.nullToZero(stockIn.getRealNum()).equals(NepUtil.nullToZero(stockIn.getUsableNum())))
            return R.fail("该入库单下的商品已被消耗，不能操作");

        // 获取商品的加权平均价
        GoodsWetPrice goodsWetPrice = goodsWetPriceService.getByGoodsIdAndGoodsTypeId(stockIn.getGoodsId(), stockIn.getGoodsTypeId());
        if (null == goodsWetPrice) return R.fail("入库商品相关加权记录获取失败");

        // 真实入库数量
        Integer realNum = NepUtil.nullToZero(stockIn.getRealNum());
        // 剩余可用的入库数
        Integer usableNum = NepUtil.nullToZero(stockIn.getUsableNum());
        // 入库金额
        Double inAmount = NepUtil.nullToZero(stockIn.getInAmount());
        // 入库商品的库存数如已使用，则计算剩余的商品价格
//        if (usableNum < realNum) {
//            // 入库金额不为0
//            if (inAmount != 0) {
//                // 计算入库商品的平均价
//                double div = DoubleUtil.div(inAmount, realNum, 4);
//                // 计算剩余数量的总价格
//                inAmount = DoubleUtil.mul(div, usableNum);
//            }
//        }

        Date time = DateUtil.getNowDatetime();
        boolean l = stockInService.setReturn(inCode, headStaffUid, headStaffName, remark, usableNum, inAmount, time);
        if (!l) return R.fail("入库单退回失败");

        // 退回入库单的库存数，扣除对应入库商品的加权平均价
        GoodsWetAvgUtil.deductGoodsWetAvgPrice(goodsWetPrice, stockIn.getGoodsName() + "-" + stockIn.getGoodsTypeName(),
                usableNum, inAmount, time);

        return R.ok();
    }


    @ApiOperation(value = "商品经销存")
    @PostMapping(value = "/goodTypeStockPageList", produces = "application/json; charset=UTF-8")
    public R<Object> goodTypeStockPageList(
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "商品名/商品规格名") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "截止日期") @RequestParam(value = "endDate", required = false) String endDate
    ) {
        Page<GoodsTypeDto> page = goodsTypeService.pageList(pageUtil, keyword, null, null);

        List<GoodsTypeDto> list = page.getRecords();

        JSONArray array = new JSONArray();
        if (CollectionUtils.isNotEmpty(list)) {
            if (StringUtils.isBlank(beginDate))
                beginDate = "2023-01-01";

            List<Long> goodsTypeIds = list.stream().map(GoodsTypeDto::getGoodsTypeId).collect(Collectors.toList());

            // 按日期获取入库记录
            Map<Long, List<WhStockIn>> stockInListMap = stockInService.listByGoodsTypeIdAndAddTimeBetween(goodsTypeIds, beginDate, endDate);
            // 按日期获取出库记录
            Map<Long, List<WhStockOutGoods>> stockOutGoodsListMap = stockOutGoodsService.listByGoodsTypeIdAndAddTimeBetween(goodsTypeIds, beginDate, endDate);

            // 加权平均价
            Map<Long, Double> wetPriceMap = new HashMap<>();
            if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate)) {
                // 按开始时间和结束时间，获取最近一次出库记录的加权平均价
                wetPriceMap = stockOutGoodsService.lastWetAvgPriceByGoodsTypeIds(beginDate, endDate, goodsTypeIds);
            } else {
                // 当前的加权平均价
                List<GoodsWetPrice> goodsWetPriceList = goodsWetPriceService.getByGoodsTypeId(goodsTypeIds);
                if (CollectionUtils.isNotEmpty(goodsWetPriceList))
                    wetPriceMap = goodsWetPriceList.stream().collect(Collectors.toMap(GoodsWetPrice::getGoodsTypeId, GoodsWetPrice::getWetAvePrice));
            }

            for (GoodsTypeDto goodsTypeDto : list) {
                JSONObject jsonObject = JsonUtil.toJsonObject(goodsTypeDto);
                Long goodsTypeId = goodsTypeDto.getGoodsTypeId();

                // 入库记录
                int inCnt = 0;
                double inAmount = 0;
                List<WhStockIn> stockInList = stockInListMap.get(goodsTypeId);
                if (CollectionUtils.isNotEmpty(stockInList)) {
                    for (WhStockIn stockIn : stockInList) {
                        inCnt += stockIn.getRealNum();
                        inAmount = DoubleUtil.sum(inAmount, stockIn.getInAmount());
                    }
                }

                // 加权平均价，保留2位
                double wetPrice = NepUtil.nullToZero(wetPriceMap.get(goodsTypeId));
                if (wetPrice > 0)
                    wetPrice = DoubleUtil.round(wetPrice, 2);

                // 出库记录
                int sendCnt = 0;
                double sendPrice = 0;
                List<WhStockOutGoods> stockOutGoodsList = stockOutGoodsListMap.get(goodsTypeId);
                if (CollectionUtils.isNotEmpty(stockOutGoodsList)) {
                    for (WhStockOutGoods stockOutGoods : stockOutGoodsList) {
                        sendCnt += stockOutGoods.getNum();
                        sendPrice = DoubleUtil.sum(sendPrice, stockOutGoods.getPrice());
                    }
                }

                jsonObject.put("inCnt", inCnt);
                jsonObject.put("wetPrice", wetPrice);
                jsonObject.put("sendCnt", sendCnt);
                jsonObject.put("sendPrice", sendPrice);
                int residueCnt = inCnt - sendCnt;
                jsonObject.put("residueCnt", residueCnt);
                double residuePrice = DoubleUtil.mul(residueCnt, wetPrice);
                jsonObject.put("residuePrice", residuePrice);

                array.add(jsonObject);
            }
        }

        PageBeanDto dto = new PageBeanDto();
        dto.setTotal(page.getTotalRow());
        dto.setList(array);

        return R.ok(dto);
    }

    @ApiOperation(value = "导出入库记录")
    @PostMapping(value = "/exportList", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportList(
            HttpServletResponse response,
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "入库单号/商品名称") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "开始日期 yyyy-MM-dd") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期 yyyy-MM-dd") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        // 默认获取本月的第一天和最后一天
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        List<WhStockIn> list = stockInService.exportList(keyword, beginDate, endDate);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("未查询到数据");

        List<WhStockInVo> voList = new ArrayList<>();
        for (WhStockIn stockIn : list) {
            WhStockInVo data = new WhStockInVo();
            if (stockIn.getInType().equals(1))
                data.setInType("采购");
            else if (stockIn.getInType().equals(2))
                data.setInType("出库退回");
            data.setPurchaseCode(stockIn.getPurchaseCode());
            data.setInCode(stockIn.getInCode());
            data.setSupplierName(stockIn.getSupplierName());
            data.setGoodsName(stockIn.getGoodsName());
            data.setGoodsTypeName(stockIn.getGoodsTypeName());
            data.setUnitPrice(stockIn.getUnitPrice());
            data.setRealNum(stockIn.getRealNum());
            data.setUsableNum(stockIn.getUsableNum());
            data.setStatusName(stockIn.getStatusName());
            data.setCreator(stockIn.getCreator());
            data.setAddTime(DateUtil.getDefaultTimeStr(stockIn.getAddTime()));

            voList.add(data);

        }

        String fileName = "入库记录";
        ExcelHandler.exportExcel(response, voList, WhStockInVo.class, fileName, "入库记录", true);
    }

    @ApiOperation(value = "商品经销存导出")
    @PostMapping(value = "/exportGoodTypeStockList", produces = "application/json; charset=UTF-8")
    public void exportGoodTypeStockList(
            HttpServletResponse response,
            @ApiParam(value = "总部员工uid") @RequestParam(value = "headStaffUid") String headStaffUid,
            @ApiParam(value = "总部员工名") @RequestParam(value = "headStaffName") String headStaffName,
            @ApiParam(value = "商品名/商品规格名") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "截止日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        List<GoodsAndTypeDto> list = goodsTypeService.goodsTypeList(keyword, null, null);

        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("未查询到数据");

        if (StringUtils.isBlank(beginDate))
            beginDate = "2023-01-01";

        List<Long> goodsTypeIds = list.stream().map(GoodsAndTypeDto::getGoodsTypeId).collect(Collectors.toList());

        // // 按日期获取入库记录
        Map<Long, List<WhStockIn>> stockInListMap = stockInService.listByGoodsTypeIdAndAddTimeBetween(goodsTypeIds, beginDate, endDate);

        // // 按日期获取出库记录
        Map<Long, List<WhStockOutGoods>> stockOutGoodsListMap = stockOutGoodsService.listByGoodsTypeIdAndAddTimeBetween(goodsTypeIds, beginDate, endDate);

        // 加权平均价
        Map<Long, Double> wetPriceMap = new HashMap<>();
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate)) {
            // 按开始时间和结束时间，获取最近一次出库记录的加权平均价
            wetPriceMap = stockOutGoodsService.lastWetAvgPriceByGoodsTypeIds(beginDate, endDate, goodsTypeIds);
        } else {
            // 当前的加权平均价
            List<GoodsWetPrice> goodsWetPriceList = goodsWetPriceService.getByGoodsTypeId(goodsTypeIds);
            if (CollectionUtils.isNotEmpty(goodsWetPriceList))
                wetPriceMap = goodsWetPriceList.stream().collect(Collectors.toMap(GoodsWetPrice::getGoodsTypeId, GoodsWetPrice::getWetAvePrice));
        }

        List<GoodsTypeInAndSendVo> voList = new ArrayList<>();
        for (GoodsAndTypeDto dto : list) {
            Long goodsTypeId = dto.getGoodsTypeId();

            // 入库记录
            int inCnt = 0;
            double inAmount = 0;
            List<WhStockIn> stockInList = stockInListMap.get(goodsTypeId);
            if (CollectionUtils.isNotEmpty(stockInList)) {
                for (WhStockIn stockIn : stockInList) {
                    inCnt += stockIn.getRealNum();
                    inAmount = DoubleUtil.sum(inAmount, stockIn.getInAmount());
                }
            }

            // 加权平均价，保留2位
            double wetPrice = NepUtil.nullToZero(wetPriceMap.get(goodsTypeId));
            if (wetPrice > 0)
                wetPrice = DoubleUtil.round(wetPrice, 2);

            // 出库记录
            int sendCnt = 0;
            double sendPrice = 0;
            List<WhStockOutGoods> stockOutGoodsList = stockOutGoodsListMap.get(goodsTypeId);
            if (CollectionUtils.isNotEmpty(stockOutGoodsList)) {
                for (WhStockOutGoods stockOutGoods : stockOutGoodsList) {
                    sendCnt += stockOutGoods.getNum();
                    sendPrice = DoubleUtil.sum(sendPrice, stockOutGoods.getPrice());
                }
            }

            GoodsTypeInAndSendVo vo = new GoodsTypeInAndSendVo();
            vo.setGoodsName(dto.getGoodsName());
            vo.setGoodsTypeName(dto.getGoodsTypeName());
            vo.setInCnt(inCnt);
            vo.setWetPrice(wetPrice);
            vo.setSendCnt(sendCnt);
            vo.setSendPrice(sendPrice);
            int residueCnt = inCnt - sendCnt;
            vo.setResidueCnt(residueCnt);
            double residuePrice = DoubleUtil.mul(residueCnt, wetPrice);
            vo.setResiduePrice(residuePrice);

            voList.add(vo);
        }

        String fileName = "商品经销存记录";
        ExcelHandler.exportExcel(response, voList, GoodsTypeInAndSendVo.class, fileName, "商品经销存记录", true);
    }

}